package com.kyrie.lib_sys.application.bookApplys.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.gson.Gson;
import com.kyrie.lib_sys.annotation.logAnnotation.OperationLog;
import com.kyrie.lib_sys.annotation.logAnnotation.OperationType;
import com.kyrie.lib_sys.common.entity.PageResult;
import com.kyrie.lib_sys.application.bookApplys.mapper.BookMapper;
import com.kyrie.lib_sys.common.pojo.dto.BookDTO;
import com.kyrie.lib_sys.common.pojo.dto.BookPageQueryDTO;
import com.kyrie.lib_sys.common.pojo.entity.Book;
import com.kyrie.lib_sys.application.bookApplys.service.BookService;
import com.kyrie.lib_sys.rocketMQ.Producer.MessageProducerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class BookServiceImpl implements BookService {

    @Autowired
    private BookMapper bookMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MessageProducerService messageProducerService;


    /**
     * 添加图书
     *
     * @param bookDTO
     */
    @Override
    public void insert(BookDTO bookDTO) {
        Book book = new Book();
        BeanUtils.copyProperties(bookDTO, book);
        bookMapper.insert(book);
    }


    /**
     * 根据id查询图书
     *
     * @param id
     * @return
     */
    @Override
    public BookDTO queryBookById(Long id) {
        Book book = new Book();
        book.setId(id);

        return bookMapper.queryBookById(book);
    }


    /**
     * 分页查询图书
     *
     * @param bookPageQueryDTO
     * @return
     */
    @OperationLog(type = OperationType.QUERY)
    @Override
    public PageResult queryPage(BookPageQueryDTO bookPageQueryDTO) {
        //1.设置起始分页
        PageHelper.startPage(bookPageQueryDTO.getPageNum(), bookPageQueryDTO.getPageSize());

        Page<Book> page = bookMapper.queryPage(bookPageQueryDTO);


        long total = page.getTotal();
        List<Book> records = page.getResult();


        PageResult pageResult = new PageResult(total, records);

        return pageResult;
    }

    /**
     * 根据条件查询图书
     *
     * @param bookDTO
     * @return
     */
    @Override
    public BookDTO queryByCondition(BookDTO bookDTO) {
        //1.构建缓存key
        String cacheKey = "BookCache:" + bookDTO.toString();
        String redisCacheValue = (String) redisTemplate.opsForValue().get(cacheKey);
        //2.缓存存在,直接返回
        if (redisCacheValue != null) {
            //2.1判断是否是之前设置的防击穿空值
            if ("NULL".equals(redisCacheValue)) {
                return null; // 明确返回null，表示数据库不存在该记录
            }
            Gson gson = new Gson();
            return gson.fromJson(redisCacheValue, BookDTO.class);
        }
        //3.缓存不存在,查数据库
        Book book = new Book();
        BeanUtils.copyProperties(bookDTO, book);
        BookDTO dbBookResult = bookMapper.queryByCondition(book);
        //4.数据库查不到,返回null,避免缓存击穿
        if (dbBookResult == null) {
            redisTemplate.opsForValue().set(cacheKey, "NULL", 1, TimeUnit.MINUTES);
            return null;
        }
        //5.数据库查到写入缓存
        Gson gson = new Gson();
        String redisResult = gson.toJson(dbBookResult);
        redisTemplate.opsForValue().set(cacheKey, redisResult, 30, TimeUnit.SECONDS);
        //6.返回结果
        return dbBookResult;
    }


    /**
     * 修改图书
     * 策略：延时双删 + MQ保底
     * @param bookDTO
     */
    @Override
    public boolean update(BookDTO bookDTO) {
        // 0. 准备缓存Key (非常重要！通常用ID而不是整个对象toString)
        String cacheKey = "book:" + bookDTO.getId(); // 使用ID作为Key更精确

        // 1. 第一次删除缓存 (清除可能存在的旧数据)
        redisTemplate.delete(cacheKey);

        // 2. 更新数据库 (核心业务操作)
        Book book = new Book();
        BeanUtils.copyProperties(bookDTO, book);
        boolean updated = bookMapper.update(book);

        if (!updated) {
            return false; // 数据库更新失败，直接返回
        }

        // 3. 延时（等待可能出现的脏读请求完成）
        try {
            Thread.sleep(500); // 延时500毫秒
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 正确处理中断异常
            // 即使中断，也继续执行后续删除操作，不抛异常
        }

        // 4. 第二次删除缓存 (清理延时期间可能被写入的脏数据)
        Boolean secondDeleteSuccess = redisTemplate.delete(cacheKey);

        // 5. 【核心保底逻辑】如果第二次同步删除失败，发送MQ消息进行异步重试
        if (Boolean.FALSE.equals(secondDeleteSuccess)) {
            log.warn("第二次缓存删除失败，发送MQ消息进行保底机制重试删除缓存，key: {}", cacheKey);
            messageProducerService.sendCacheDeleteMessage(cacheKey);// 调用发送MQ的方法
        }
        return updated;
    }

    /**
     * 删除图书
     *
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        Book book = new Book();
        book.setId(id);
        bookMapper.deleteById(book);
    }


    /**
     * 批量删除图书
     *
     * @param ids
     */
    @Override
    public void deleteBatch(List<Long> ids) {
        bookMapper.deleteBatch(ids);
    }

    /**
     * 批量添加图书
     *
     * @param bookDTOS
     */
    @Override
    public void insertBatch(List<BookDTO> bookDTOS) {
//        List<Book> bookList = bookDTOS.stream().map(bookDTO -> {
//            Book book = new Book();
//            BeanUtils.copyProperties(bookDTO, book);
//            return book;
//        }).toList();
        List<Book> bookList = new ArrayList<>();
        if (bookDTOS != null) {
            for (BookDTO bookDTO : bookDTOS) {
                if (bookDTO != null) {
                    Book book = new Book();
                    BeanUtils.copyProperties(bookDTO, book);
                    bookList.add(book);
                }
            }
        }
        bookMapper.insertBatch(bookList);
    }


}
